//
// Created by root on 19-7-28.
//

#include <dlfcn.h>
#include "hook_jvm.h"
#include "log_utils.h"
#include "AndHook.h"
#include "hook_fork.h"
#include "hook_parse_app.h"
#include "inject_compacter.h"
#include "hook_sys_attach.h"
#include "hook_gss.h"
#include "hook_sys_properties.h"
#include "hook_camera_v1.h"
#include "hook_audio_record.h"
#include "hook_execve.h"
#include "jni_utils.h"
#include "process_utils.h"
#include "hook_selinux_check.h"
#include "hook_app_create.h"

#define TAG "HookJVM"

static bool use_ptrace_entry=false;
void do_hooks(JavaVM *vm, JNIEnv *env){
    if(!use_ptrace_entry)
        AKSetCacheDirectory("/data/system");
    if(get_process_name(getpid())=="system_server")
        AKSetCacheDirectory("/data/system");
    if(AKInitializeOnce(env,vm)!=JNI_OK){
        LOGE("fail to initialize AndHook\n");
    }

    hook_fork_and_specialize(env);
    hook_parse_base_app(env);

    hook_execve();//disable dex2oat

    //inject_compacter(env);//目前政策是app自己加载
    hook_call_app_oncreate(env);

    hook_sm_add_service(env);//进入system_server
    hook_sys_get_properties(env);
    hook_get_sys_service(env);
    hook_camera_v1(env);
    hook_audio_record_setup(env);



    LOGD("SystemDebugger has been initialized\n");
}

extern "C" JNIEXPORT int hook_entry(char* reserved){
    int pid=getpid();
    std::string process_name=get_process_name(pid);
    if(process_name.find("servicemanager")!=std::string::npos){
        LOGD("hook_entry in servicemanager\n");
        hook_selinux_check_access();
        return 0;
    }
    JNIEnv *env= get_jni_env();
    if(!env) {

        LOGE("fail to get JNIEnv in process:%s(%d)\n",get_process_name(pid).c_str(),pid);
        return JNI_ERR;
    }
    JavaVM *vm= nullptr;
    jint get_jvm_ret=env->GetJavaVM(&vm);
    if(get_jvm_ret==JNI_OK) {
        use_ptrace_entry=true;
        do_hooks(vm, env);
    }
    LOGD("hook_entry finished\n");
    return 0;
}

typedef jint (*func_create_jvm)(JavaVM**, JNIEnv**, void*);

static func_create_jvm old_create_jvm= nullptr;

jint my_create_jvm(JavaVM** p_vm, JNIEnv** p_env, void* reserved){
    if(!old_create_jvm){
        LOGE("fail to get old_create_jvm\n");
        return JNI_ERR;
    }
    jint ret=old_create_jvm(p_vm,p_env,reserved);
    JavaVM *vm=*p_vm;
    JNIEnv *env=*p_env;

    do_hooks(vm,env);

    LOGD("old_create_jvm ret:%d\n",ret);
    return ret;
}

void hook_create_jvm() {
    int uid=getuid();
    if(uid!=0){
        LOGE("%d no permission to hook create_jvm\n",uid);
        return;
    }
    LOGI(__FUNCTION__);
    void *create_jvm_symbol = dlsym(RTLD_DEFAULT, "JNI_CreateJavaVM");
    LOGI("JNI_CreateJavaVM = %p", create_jvm_symbol);
    if (create_jvm_symbol) {
        AKHookFunction(create_jvm_symbol, reinterpret_cast<void*>(my_create_jvm),
                       reinterpret_cast<void **>(&old_create_jvm));
    } //if
    LOGD("old_create_jvm:%p\n",old_create_jvm);
}
